package com.tool;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.log.StaticLog;
import ntd.util.ComConfig;
import ntd.util.fun.ComFun;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: liuwenju
 * @date: 2023/8/11 14:55
 * @version: 1.0
 */
public class ToolRedisson {

    public static ToolRedisson me = new ToolRedisson();

    public final static Map<String, ToolRedisson> REDISSON_MAP = new HashMap<>();

    public RedissonClient redisson;

    public ToolRedisson() {
        redisson = init(ComConfig.REDIS_DB_INDEX);
    }

    public ToolRedisson(int db_index) {
        redisson = init(db_index);
    }

    public static ToolRedisson me(int db_index) {
        String key = "chche:" + db_index;
        ToolRedisson toolRedisson = REDISSON_MAP.get(key);
        if (ObjectUtil.isNull(toolRedisson)) {
            REDISSON_MAP.put(key, toolRedisson = new ToolRedisson(db_index));
        }
        return toolRedisson;
    }

    private static RedissonClient init(int db_index) {
        Config config = new Config();
        // 设置模式
//        config.setTransportMode(TransportMode.EPOLL);
        // 使用单节点模式
        SingleServerConfig singleServerConfig = config.useSingleServer();
        // 集群扫描间隔配置
//        singleServerConfig.setScanInterval(2000);
        // 添加redis集群节点地址 可以用"rediss://"来启用SSL连接
        singleServerConfig.setAddress(StrUtil.format("redis://{}:{}", ComConfig.REDIS_HOST, ComConfig.REDIS_PORT));
        singleServerConfig.setPassword(ComConfig.REDIS_PASS);
        singleServerConfig.setDatabase(db_index);

        // 创建Redisson客户端
        return Redisson.create(config);
    }

    public boolean is_idempotent(String key, String msg) {
        return is_idempotent(key, msg, 60);
    }

    public boolean is_idempotent(String key, String msg, int time) {
        // 使用RSet实现幂等判断
        RSet<String> idempotentSet = redisson.getSet("idempotent:" + key);

        // 判断当前请求是否已经存在于Set中
        if (idempotentSet.contains(msg)) {
            // 已存在，表示重复请求
            return false;
        } else {
            // 不存在，将请求添加到Set中，并设置过期时间（可根据具体业务需求设置）
            idempotentSet.add(msg);
            // 设置幂等过期时间
            idempotentSet.expire(Duration.ofSeconds(time));
            return true;
        }
    }

    public void lock_run(String key, ComFun.FunNoException funNoException) {
        RLock lock = redisson.getLock("lock:" + key);
        try {
            lock.lock(60, TimeUnit.SECONDS);
            funNoException.accept();
        } finally {
            lock.unlock();
        }
    }

    public boolean throttle(String requestKey, int time) {
        // 使用RRateLimiter实现节流功能
        RRateLimiter rateLimiter = redisson.getRateLimiter("throttle:" + requestKey);
        // 设置每秒允许的请求数
        rateLimiter.trySetRate(RateType.PER_CLIENT, 1, time, RateIntervalUnit.SECONDS);
        // 尝试获取指定数量的许可
        return rateLimiter.tryAcquire(1);
    }

    public void throttle_run(String requestKey, ComFun.FunNoException funNoException, int time) {
        String throttle_key = DigestUtil.sha256Hex(requestKey);
        if (throttle(throttle_key, time)) {
            funNoException.accept();
        }
    }

    public void set(String key, String value, Duration duration) {
        // 获取RBucket对象
        RBucket<String> rBucket = redisson.getBucket(key, new StringCodec());
        // 设置字符串值
        if (ObjectUtil.isNull(duration)) {
            rBucket.set(value);
        } else {
            rBucket.set(value, duration);
        }
    }

    public void set(String key, String value) {
        set(key, value, null);
    }

    public String get(String key) {
        // 获取RBucket对象
        RBucket<String> rBucket = redisson.getBucket(key, new StringCodec());
        // 获取字符串值
        return rBucket.get();
    }

    public String get(String key, String new_val) {
        return get(key, () -> new_val, null);
    }

    public String get(String key, ComFun.FunOutNoException<String> fun) {
        return get(key, fun, null);
    }

    public String get(String key, ComFun.FunOutNoException<String> fun, Duration duration) {
        // 获取RBucket对象
        RBucket<String> rBucket = redisson.getBucket(key, new StringCodec());
        // 获取字符串值
        String value = rBucket.get();
        // 如果值为空，则设置新值并返回新值
        if (StrUtil.isBlank(value) && ObjectUtil.isNotNull(fun)) {
            if (ObjectUtil.isNull(duration)) {
                rBucket.set(value = fun.accept());
            } else {
                rBucket.set(value = fun.accept(), duration);
            }
        }
        // 如果值不为空，则直接返回值
        return value;
    }

    public static void main(String[] args) {
        me(7).set("test", "sss");
        StaticLog.info(me(7).get("test"));
    }

}
